package ${package};

import java.util.List;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.util.SparseArray;
<#list imports as import>
import ${import};
</#list>

<#list db.entities as entity>
import ${contractBaseClass}.${entity.entityNamePlural}Base;
</#list>

public abstract class ${providerBaseName} extends ContentProvider {
	protected SQLiteOpenHelper mSQLiteOpenHelper;

	interface Tables {
		<#list db.entities as entity>
		<#assign entityPluralUpper = entity.entityNamePlural?upper_case>
		String ${entityPluralUpper} = "${entity.tableName}";
		</#list>
	}

	<#assign nextMatchCode = 0>
	<#list db.entities as entity>
	<#assign entityPluralUpper = entity.entityNamePlural?upper_case>
	protected static final int ${entityPluralUpper} = ${nextMatchCode};
	protected static final int ${entityPluralUpper}_ID = ${nextMatchCode + 1};
	<#assign nextMatchCode = nextMatchCode + 2>
	</#list>

	protected static final int LAST_AUTO_CODE = ${nextMatchCode - 1};

	protected static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
	protected static final SparseArray<String> sTypesByCode = new SparseArray<String>();

	static {
		<#list db.entities as entity>
		<#assign entityPlural = entity.entityNamePlural>
		<#assign entityPluralUpper = entityPlural?upper_case>
		<#assign entityPluralLower = entityPlural?lower_case>
		matchUri("${entityPluralLower}", ${entityPluralUpper}, ${entityPlural}Base.CONTENT_TYPE);
		matchUri("${entityPluralLower}/#", ${entityPluralUpper}_ID, ${entityPlural}Base.CONTENT_ITEM_TYPE);
		</#list>
	}

	protected static void matchUri(String path, int code, String contentType) {
		sUriMatcher.addURI(${contractBaseName}.CONTENT_AUTHORITY, path, code);
		sTypesByCode.put(code, contentType);
	}

	@Override
	public boolean onCreate() {
		mSQLiteOpenHelper = ${db.factoryClass}.getDatabaseHelper(getContext());
		return true;
	}

	@Override
	public String getType(Uri uri) {
		final int matchCode = sUriMatcher.match(uri);
		final String contentType = sTypesByCode.get(matchCode);

		if (contentType == null) {
			throw new UnsupportedOperationException("Unknown uri: " + uri);
		}

		return contentType;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
						String sortOrder) {
		final SQLiteDatabase db = mSQLiteOpenHelper.getReadableDatabase();
		final SelectionBuilder builder = buildQuerySelection(uri);
		Cursor cursor = builder.where(selection, selectionArgs).query(db, projection, sortOrder);
		// TODO: the notification URI needs to be more correct here
		cursor.setNotificationUri(getContext().getContentResolver(), uri);
		return cursor;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		final SQLiteDatabase db = mSQLiteOpenHelper.getWritableDatabase();
		final int matchCode = sUriMatcher.match(uri);
		switch (matchCode) {
			<#list db.entities as entity>
			<#assign entityPlural = entity.entityNamePlural>
			<#assign entityPluralUpper = entityPlural?upper_case>
			<#assign entityPluralLower = entityPlural?lower_case>
			case ${entityPluralUpper}: {
				final long _id = db.insertOrThrow(Tables.${entityPluralUpper}, null, values);
				getContext().getContentResolver().notifyChange(uri, null, false);
				return ${entityPlural}Base.buildItemUri(_id);
			}
			</#list>
		}

		throw new UnsupportedOperationException("Unknown uri: " + uri);
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		final SQLiteDatabase db = mSQLiteOpenHelper.getWritableDatabase();
		final SelectionBuilder builder = buildSelection(uri);
		getContext().getContentResolver().notifyChange(uri, null, false);
		return builder.where(selection, selectionArgs).update(db, values);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		final SQLiteDatabase db = mSQLiteOpenHelper.getWritableDatabase();
		final SelectionBuilder builder = buildSelection(uri);
		getContext().getContentResolver().notifyChange(uri, null, false);
		return builder.where(selection, selectionArgs).delete(db);
	}

	protected final SelectionBuilder buildQuerySelection(Uri uri) {
		final SelectionBuilder builder = new SelectionBuilder();
		final int matchCode = sUriMatcher.match(uri);
		final List<String> pathSegments = uri.getPathSegments();
		return buildQuerySelection(uri, pathSegments, matchCode, builder);
	}

	protected final SelectionBuilder buildSelection(Uri uri) {
		final SelectionBuilder builder = new SelectionBuilder();
		final int matchCode = sUriMatcher.match(uri);
		final List<String> pathSegments = uri.getPathSegments();
		return buildSelection(uri, pathSegments, matchCode, builder);
	}

	protected SelectionBuilder buildQuerySelection(Uri uri, List<String> pathSegments, int matchCode, SelectionBuilder builder) {
		switch (matchCode) {
			// TODO: views?
		}

		return buildSelection(uri, uri.getPathSegments(), matchCode, builder);
	}

	protected SelectionBuilder buildSelection(Uri uri, List<String> pathSegments, int matchCode, SelectionBuilder builder) {
		switch (matchCode) {
			<#list db.entities as entity>
			<#assign entityPlural = entity.entityNamePlural>
			<#assign entityPluralUpper = entityPlural?upper_case>
			<#assign entityPluralLower = entityPlural?lower_case>
			case ${entityPluralUpper}: {
				return builder.table(Tables.${entityPluralUpper});
			}
			case ${entityPluralUpper}_ID: {
				final String _id = pathSegments.get(1);
				return builder.table(Tables.${entityPluralUpper}).where(${entityPlural}Base._ID + "=?", _id);
			}
			</#list>
		}

		throw new UnsupportedOperationException("Unknown uri: " + uri);
	}
}
